package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollStreamUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsRecord;
import com.tianji.learning.domain.vo.PointsStatisticsVO;
import com.tianji.learning.enums.PointsRecordType;
import com.tianji.learning.mapper.PointsRecordMapper;
import com.tianji.learning.service.IPointsRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学习积分记录，每个月底清零 服务实现类
 * </p>
 *
 * @author 赵博凯
 * @since 2025-10-29
 */
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements IPointsRecordService {

    private final StringRedisTemplate redisTemplate;

    @Override
    public List<PointsStatisticsVO> queryTodayMyPoints() {
        // 1.查询统计当前用户当天获取积分情况（分组查询） SELECT type, SUM(points) AS points FROM points_record WHERE user_id = ? AND create_time BETWEEN ? AND ? GROUP BY type
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime begin = DateUtils.getDayStartTime(now);
        LocalDateTime end = DateUtils.getDayEndTime(now);

        List<PointsRecord> list = this.query()
                .select("type", "sum(points) as points")
                .eq("user_id", UserContext.getUser())
                .between("create_time", begin, end)
                .groupBy("type")
                .list();
        if(ObjectUtils.isEmpty(list)){
            return Collections.emptyList();
        }
        // 2.封装volist并返回
        /*List<PointsStatisticsVO> voList = new ArrayList<>(list.size());
        for(PointsRecord pointsRecord : list){
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(pointsRecord.getType().getDesc());
            vo.setMaxPoints(pointsRecord.getType().getMaxPoints());
            vo.setPoints(pointsRecord.getPoints());
            voList.add(vo);
        }*/


        List<PointsStatisticsVO> voList = list.stream().map(po -> {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(po.getType().getDesc());
            vo.setMaxPoints(po.getType().getMaxPoints());
            vo.setPoints(po.getPoints());
            return vo;

        }).collect(Collectors.toList());

        //3、处理没有积分值的积分类型
        Set<String> typeSet = CollStreamUtil.toSet(voList, PointsStatisticsVO::getType);
        List<PointsRecordType> types = Arrays.stream(PointsRecordType.values())
                .filter(p -> !typeSet.contains(p.getDesc()))
                .collect(Collectors.toList());
        for (PointsRecordType type : types) {
            PointsStatisticsVO vo = new PointsStatisticsVO();
            vo.setType(type.getDesc());
            vo.setMaxPoints(type.getMaxPoints());
            vo.setPoints(0);
            voList.add(vo);

        }

        return voList;
    }

    @Override
    public void addPointsRecord(Long userId, PointsRecordType type, int points) {
        // 1、判断当前积分类型，是否有每日积分上限
        int maxPoints = type.getMaxPoints();

        //2、如果有，判断当前用户，通过读积分类型，获取的积分总额是否超过每日上限
        if (maxPoints > 0) {
            //2.1、查询【当前用户】【今日】通过读【积分类型】已获取的【积分总数】 SELECT * FROM points_record WHERE user_id = ? AND type = ? AND create_time BETWEEN ? AND ?
            int currentDayPoints = queryCurrentDayPoints(userId, type);

            //2.2、判断是否超过了每日上限
            if (currentDayPoints >= maxPoints) {
                //2.3、如果超过了，则不添加积分记录，直接结束
                return;
            }


            //2.4、如果没超过，处理 已有积分 + 本次待加积分 > 积分上限的情况，不能直接加了，而是加：上限-已有积分 的差值
            if (currentDayPoints + points > maxPoints) {
                points = maxPoints - currentDayPoints;
            }
        }

        //3.如果没有，则添加积分记录
        PointsRecord pointsRecord = new PointsRecord().setUserId(userId).setType(type).setPoints(points);
        this.save(pointsRecord);

        //4.累加当前用户的积分至 redis zset中，形成实时积分榜单
         //4.1、组装zset排行榜key（boards:202510）
         String key = RedisConstants.POINTS_BOARDS_KEY_PREFIX + LocalDate.now().format(DateUtils.DATE_SUFFIX_FORMATTER);
        //4.2、累加积分
        redisTemplate.opsForZSet().incrementScore(key,String.valueOf(userId),points);
    }

    private int queryCurrentDayPoints2(Long userId, PointsRecordType type) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime begin = DateUtils.getDayStartTime(now);
        LocalDateTime end = DateUtils.getDayEndTime(now);

        PointsRecord record = this.query()
                .select("sum(points) as points")
                .eq("user_id", userId)
                .eq("type", type)
                .between("create_time", begin, end)
                .one();
        return ObjectUtils.isEmpty(record) || ObjectUtils.isEmpty(record.getPoints()) ? 0 : record.getPoints();
    }
    private int queryCurrentDayPoints(Long userId, PointsRecordType type) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime begin = DateUtils.getDayStartTime(now);
        LocalDateTime end = DateUtils.getDayEndTime(now);

        LambdaQueryWrapper<PointsRecord> queryWrapper = Wrappers.<PointsRecord>lambdaQuery()
                .eq(PointsRecord::getUserId, userId)
                .eq(PointsRecord::getType, type)
                .between(PointsRecord::getCreateTime, begin, end);

        Integer points = this.getBaseMapper().queryCurrentDayPoints(queryWrapper);

        return ObjectUtils.isEmpty(points) ? 0 : points;
    }



}
